package com.gitee.kamismile.gatewayAgent.server.handler;

import com.gitee.kamismile.gatewayAgent.common.APPChannel;
import com.gitee.kamismile.gatewayAgent.protobuf.Message;
import com.gitee.kamismile.stone.commmon.util.JsonUtil;
import com.gitee.kamismile.stone.commmon.util.SnowflakeIdWorker;
import com.gitee.kamismile.stone.commmon.util.ValueUtils;
import com.google.gson.JsonSyntaxException;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.SimpleChannelInboundHandler;
import com.gitee.kamismile.gatewayAgent.server.bootstrap.GatewayAgentConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.*;

/**
 * Created by lidong on 2017/2/8.
 */

public class GateWayServerHandler extends SimpleChannelInboundHandler<Message.RouterMessage> {
    private final Logger logger = LoggerFactory.getLogger("bLog");

    private SnowflakeIdWorker snowflakeIdWorker;

    private GatewayAgentConstant gatewayAgentConstant;

    private long seq;

    private String reqCmd;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
//        Channel channel = ctx.channel();
//        ChannelId channelId = channel.id();
//        APPChannel.channels.add(channel);
//        APPChannel.channelsText.put(channelId.asLongText(),channelId);
        super.channelActive(ctx);
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message.RouterMessage msgRequest) throws Exception {
        List<Message.RouterRequest> requestList = msgRequest.getRequestList();
        if (CollectionUtils.isEmpty(requestList)) {
            return;
        }

        String clientId = getClientIdString(ctx);
        String remoteAddress = ctx.channel().remoteAddress().toString();
        long startTime = System.currentTimeMillis();


        for (Message.RouterRequest request : requestList) {
//            logger.trace("request:\n{}",request);
            reqCmd = request.getCmd().getCommand();
            seq = request.getSeq();

            Message.RouterResponse.Builder resp = Message.RouterResponse.newBuilder();
            String data = new String(request.getSerializedData().toByteArray(), "utf-8");
            Map<String, Object> dataJson = ValueUtils.isNull(data) ? new HashMap<String, Object>() : JsonUtil.json2Map(data);
            dataJson.put("cmd", reqCmd);
            dataJson.put("seq", seq);
            dataJson.put("traceId", snowflakeIdWorker.nextId());
            dataJson.put("clientId", clientId);
            dataJson.put("remoteAddress", remoteAddress);

            String reqAdress = reqCmd;
            if (reqAdress.startsWith("url")) {
                reqAdress = "url";
            } else if (reqAdress.startsWith("msg")) {
                reqAdress = "msg";

                try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(dataJson.get("token").toString())));) {
                    Map channelId = (Map) ois.readObject();
                    Map.Entry onlyElement = (Map.Entry) channelId.entrySet().iterator().next();
                    onlyElement.setValue(reqAdress);
//                    dataJson.putAll(channelId);
                }
            }else if(reqAdress.equals("client@connect@heart")){

            }

            if (reqAdress.contains("auth")) {
                Channel channel = ctx.channel();
                ChannelId channelId = channel.id();
                APPChannel.tokenChannels.put(ValueUtils.isStringNull(dataJson.get("token")), channelId.asLongText());
                APPChannel.channelTokens.put(channelId.asLongText(), ValueUtils.isStringNull(dataJson.get("token")));
                APPChannel.channels.add(channel);
                APPChannel.channelsText.put(channelId.asLongText(),channelId);
            }


        }

        Message.RouterMessage.Builder msg = Message.RouterMessage.newBuilder();
        ctx.writeAndFlush(msg);
    }

    private String getClientIdString(ChannelHandlerContext ctx) throws IOException {
        ChannelId channelId = ctx.channel().id();
        String clientId = channelId.asLongText();
        return clientId;
    }


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

        Message.RouterMessage.Builder msg = Message.RouterMessage.newBuilder();
        Message.RouterResponse.Builder resp = Message.RouterResponse.newBuilder();
        resp.setSeq(ValueUtils.isLongNull(seq));
        resp.setRouter(gatewayAgentConstant.getRouter());
        Message.Command.Builder cmd = Message.Command.newBuilder();
        cmd.setCommand(ValueUtils.isStringNull(reqCmd));

        if (cause instanceof JsonSyntaxException) {
            Message.Result.Builder result = Message.Result.newBuilder();
            resp.setCmd(cmd);
            result.setCode(2);
            resp.setResult(result);
            msg.addResponse(resp);
            ctx.writeAndFlush(msg);
            return;
        }
//        String token = APPChannel.channelTokens.remove(ctx.channel().id().asLongText());
//        if(StringUtils.isNotBlank(token)){
//            APPChannel.tokenChannels.remove(token);
//        }
//        APPChannel.channels.remove(ctx.channel());
//        APPChannel.channelsText.remove(ctx.channel().id().asLongText());
        ctx.close();
        logger.error(ExceptionUtils.getStackTrace(cause));
        cause.printStackTrace();
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        String token = APPChannel.channelTokens.remove(ctx.channel().id().asLongText());
        if(StringUtils.isNotBlank(token)){
            APPChannel.tokenChannels.remove(token);
        }
        APPChannel.channels.remove(ctx.channel());
        APPChannel.channelsText.remove(ctx.channel().id().asLongText());
        super.channelUnregistered(ctx);
    }


    public SnowflakeIdWorker getSnowflakeIdWorker() {
        return snowflakeIdWorker;
    }

    public void setSnowflakeIdWorker(SnowflakeIdWorker snowflakeIdWorker) {
        this.snowflakeIdWorker = snowflakeIdWorker;
    }

    public GatewayAgentConstant getGatewayAgentConstant() {
        return gatewayAgentConstant;
    }

    public void setGatewayAgentConstant(GatewayAgentConstant gatewayAgentConstant) {
        this.gatewayAgentConstant = gatewayAgentConstant;
    }


    public long getSeq() {
        return seq;
    }

    public void setSeq(long seq) {
        this.seq = seq;
    }

    public String getReqCmd() {
        return reqCmd;
    }

    public void setReqCmd(String reqCmd) {
        this.reqCmd = reqCmd;
    }
}
